%{ open Ast %}
%{ open Operator %}
%{ open Type %}

%token SEMI LPAREN RPAREN LBRACE RBRACE LLIST RLIST LVECTOR RVECTOR COMMA 
%token MINUS NOT
%token PLUS MINUS TIMES DIVIDE ASSIGN INNERP REMIND
%token EQ NEQ LT LEQ GT GEQ LAND LOR
%token IF THEN ELSE ELSEIF ENDIF WITH DO DONE
%token INT FLOAT VECTOR LIST RINT RFLOAT STR QUOT
%token <int> LINT
%token <float> LFLOAT
%token <string> ID
%token <string> LSTR
%token EOF

%left NOT
%left EQ NEQ
%left LAND LOR
%left LT GT LEQ GEQ
%left PLUS MINUS
%left TIMES DIVIDE INNERP REMIND

%start program
%type <Ast.program> program

%%

program:
   /* nothing */ { [] }
 | dclr program { ($1 :: $2) }
 
formals_opt:
    LPAREN RPAREN { [] }
  | LPAREN formal_list RPAREN  { List.rev $2 }

formal_list:
    formal  { [$1] }
  | formal_list COMMA formal { $3 :: $1 }

formal:
    tp ID { ($1, $2) }

stmt_list:
    stmt  { [$1] }
  | stmt_list stmt { $1@[$2] }

dclr:
    tp ID formals_opt ASSIGN expr { FDclr($1, $2, $3, $5) }
  | tp ID ASSIGN expr { VDclr($1, $2, $4) }


stmt:
    dclr { $1 }

else_list:
    ELSE expr { $2 }
  | ELSEIF expr THEN expr else_list { If($2, $4, $5) }

expr:
    LINT             { LInt($1) }
  | LFLOAT           { LFloat($1) }
  | LBRACE expr_list RBRACE     { LList($2) }
  | LVECTOR expr_list RVECTOR   { LVctr($2) }
  | LPAREN expr_tuple RPAREN     { LTple($2) }
  | LSTR             { LString($1) }
  | ID               { Id($1) }
  | MINUS expr       { Uop(Minus, $2) }
  | NOT expr         { Uop(Not, $2) }
  | expr PLUS   expr { Binop($1, Add,   $3) }
  | expr MINUS  expr { Binop($1, Sub,   $3) }
  | expr TIMES  expr { Binop($1, Mult,  $3) }
  | expr DIVIDE expr { Binop($1, Div,   $3) }
  | expr REMIND expr { Binop($1, Rmndr, $3) }
  | expr INNERP expr { Binop($1, Innrp, $3) }
  | expr LAND   expr { Binop($1, Land,  $3) }
  | expr LOR    expr { Binop($1, Lor,   $3) }
  | expr EQ     expr { Binop($1, Equal, $3) }
  | expr NEQ    expr { Binop($1, Neq,   $3) }
  | expr LT     expr { Binop($1, Less,  $3) }
  | expr LEQ    expr { Binop($1, Leq,   $3) }
  | expr GT     expr { Binop($1, Greater,  $3) }
  | expr GEQ    expr { Binop($1, Geq,   $3) }
  | ID LPAREN actuals_opt RPAREN { Call($1, $3) }
  | LPAREN expr RPAREN { $2 }
  | ID LLIST expr RLIST { Elmt($1, $3) }
  | IF expr THEN expr else_list ENDIF { If($2, $4, $5) }
  | WITH stmt_list DO expr DONE { Scope($2, $4) }

expr_list:
    expr  { [$1] }
  | expr_list COMMA expr { $3 :: $1 }

expr_tuple:
    expr COMMA expr { $3::[$1] }
  | expr_tuple COMMA expr { $3 :: $1 }

actuals_opt:
    /* nothing */ { [] }
  | actuals_list  { List.rev $1 }

actuals_list:
    expr                    { [$1] }
  | actuals_list COMMA expr { $3 :: $1 }
  
tp:
    FLOAT  { Float }
  | INT    { Int }
  | VECTOR { Vector(0) }
  | RINT   { RInt }
  | RFLOAT { RFloat }
  | LIST   { List }
  | STR    { Str }
